﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BusinessModel;
using EntityDataModel;
using System.ComponentModel;
using System.Data.Objects.DataClasses;
using System.Data;
using System.Data.Objects;
using System.Data.Common;
using System.Data.SqlClient;
using BaseUtilities;

namespace Controller.DataProvider
{
    public abstract class GenericProvider<TModel> : BaseProvider where TModel : EntityModel
    {
        //public GenericProvider() { }
        //public GenericProvider(string pEntityName)
        //{
        //    EntityName = pEntityName;
        //}

        public string EntityName { get; set; }

        #region abstract Methods
        ////----------------------------------------
        //protected abstract EntityKey EntityKey
        //{
        //    get;
        //    set;
        //}
        //----------------------------------------
        public abstract EntityObject CreateEntity();
        //----------------------------------------
        public abstract TModel CreateModel();

        //----------------------------------------
        public abstract void ToEntity(TModel pModel, EntityObject pEntity, params EnumFieldCopy[] pEnumFieldCopys);
        //----------------------------------------
        public abstract void ToModel(EntityObject pEntity, TModel pModel, params EnumFieldCopy[] pEnumFieldCopys);
        #endregion abstract Methods

        #region Public Methods
        //----------------------------------------
        public ResultModel Insert(TModel pModel)
        {
            bool result = false;
            using (ManageStoreEntities entities = new ManageStoreEntities())
            {
                // ToEntity.
                EntityObject oEntity = CreateEntity();
                ToEntity(pModel, oEntity, EnumFieldCopy.Created, EnumFieldCopy.Modified);
                entities.AddObject(EntityName, oEntity);
                entities.SaveChanges();
                result = true;
            }
            return new ResultModel(result);
        }
        //----------------------------------------
        public ResultModel Update(TModel pModel, EntityKey pEntityKey)
        {
            bool result = false;
            using (ManageStoreEntities entities = new ManageStoreEntities())
            {
                // ToEntity.
                EntityObject oEntity = entities.GetObjectByKey(pEntityKey) as EntityObject;
                if (oEntity != null)
                {
                    ToEntity(pModel, oEntity, EnumFieldCopy.Modified);
                    //entities.Attach(oEntity);
                    //entities.ObjectStateManager.GetObjectStateEntry(oEntity).SetModified();
                    //entities.Refresh(System.Data.Objects.RefreshMode.ClientWins, oEntity);
                    entities.SaveChanges();
                    result = true;
                }
            }
            return new ResultModel(result);
        }
        //----------------------------------------
        public ResultModel Save(TModel pModel, EntityKey pEntityKey)
        {
            ResultModel oResultModel = new ResultModel();
            oResultModel.HasError = true;
            using (ManageStoreEntities entities = new ManageStoreEntities())
            {
                object ob;
                entities.TryGetObjectByKey(pEntityKey, out ob);
                EntityObject oEntity = ob as EntityObject;
                if (oEntity == null)
                {
                    oEntity = CreateEntity();
                    ToEntity(pModel, oEntity, EnumFieldCopy.Created, EnumFieldCopy.Modified);
                    entities.AddObject(EntityName, oEntity);
                }
                else
                {
                    ToEntity(pModel, oEntity, EnumFieldCopy.Modified);
                }
                try
                {
                    entities.SaveChanges();
                    oResultModel.HasError = false;
                    oResultModel.Result = oEntity.EntityKey.EntityKeyValues.Single().Value;
                }
                catch (Exception ex)
                {
                    ResultModel oModelResult = GetResultModel(ex);
                    return oModelResult;
                }
            }
            return oResultModel;
        }
        //----------------------------------------
        public ResultModel DeleteById(EntityKey pEntityKey)
        {
            bool result = false;
            using (ManageStoreEntities entities = new ManageStoreEntities())
            {
                object ob;
                entities.TryGetObjectByKey(pEntityKey, out ob);
                EntityObject oEntity = ob as EntityObject;
                if (oEntity != null)
                {
                    try
                    {
                        entities.DeleteObject(oEntity);
                        entities.SaveChanges();
                        result = true;
                    }
                    catch (Exception ex)
                    {
                        ResultModel oModelResult = GetResultModel(ex);
                        return oModelResult;
                    }
                }
            }
            return new ResultModel(result);
        }
        //----------------------------------------
        private ResultModel GetResultModel(Exception pEx)
        {
            ResultModel oModelResult = new ResultModel();
            SqlException sqle = pEx as SqlException;
            while (!(pEx is SqlException) && pEx.InnerException != null)
            {
                pEx = pEx.InnerException;
                sqle = pEx as SqlException;
            }
            if (sqle != null)
            {
                oModelResult.HasError = true;
                // Foreignkey constraint = 547;
                oModelResult.ErrorNumber = sqle.Number;
                oModelResult.Message = pEx.Message;
                oModelResult.Exception = pEx;
            }
            return oModelResult;
        }
        //----------------------------------------
        public ResultModel GetById(EntityKey pEntityKey)
        {
            TModel result = null;
            using (ManageStoreEntities entities = new ManageStoreEntities())
            {
                object ob;
                entities.TryGetObjectByKey(pEntityKey, out ob);
                EntityObject oEntity = ob as EntityObject;
                if (oEntity != null)
                {
                    result = CreateModel();
                    ToModel(oEntity, result, EnumFieldCopy.All);
                }
            }
            return new ResultModel(result);
        }
        //----------------------------------------
        public ResultModel GetAll()
        {
            IList<TModel> result = new List<TModel>();
            using (ManageStoreEntities entities = new ManageStoreEntities())
            {
                List<EntityObject> lst = entities.CreateQuery<EntityObject>(@"select value " + EntityName + " from " + QualifyName + "." + EntityName + " as " + EntityName).ToList();
                lst.ForEach((item) =>
                {
                    TModel oTModel = CreateModel();
                    ToModel(item, oTModel, EnumFieldCopy.All);
                    result.Add(oTModel);
                });
            }
            return new ResultModel(result);
        }
        //----------------------------------------
        public ResultModel GetIdName(object pId)
        {
            IdNameModel result = null;
            using (ManageStoreEntities entities = new ManageStoreEntities())
            {
                string sQuery = @"select " + EntityName + ".Id, " + EntityName + ".Name from " + QualifyName + "." + EntityName + " as " + EntityName + " where " + EntityName + ".Id = @Id";
                DbDataRecord item = entities.CreateQuery<DbDataRecord>(sQuery, new ObjectParameter("Id", pId)).FirstOrDefault();
                if (item != null)
                {
                    result = new IdNameModel(item.GetValue(0), item.GetValue(1).ToString());
                }
            }
            return new ResultModel(result);
        }
        //----------------------------------------
        public ResultModel GetIdNameAll()
        {
            IList<IdNameModel> result = new List<IdNameModel>();
            using (ManageStoreEntities entities = new ManageStoreEntities())
            {
                string sQuery = @"select " + EntityName + ".Id, " + EntityName + ".Name from " + QualifyName + "." + EntityName + " as " + EntityName;
                List<DbDataRecord> query = entities.CreateQuery<DbDataRecord>(sQuery).ToList();
                query.ForEach((item) =>
                    {
                        IdNameModel oIdNameModel = new IdNameModel(item.GetValue(0), item.GetValue(1).ToString());
                        result.Add(oIdNameModel);
                    });
                //result = (from item in query
                //          select new IdNameModel()
                //          {
                //              Id = item.GetValue(0),
                //              Name = item.GetValue(1).ToString()
                //          }).ToList();
            }
            return new ResultModel(result);
        }
        //----------------------------------------
        public ResultModel GetIdNameAll(string pIdColumn, string pNameColumn)
        {
            IList<IdNameModel> result = new List<IdNameModel>();
            using (ManageStoreEntities entities = new ManageStoreEntities())
            {
                string sQuery = @"select " + EntityName + "." + pIdColumn + "," + EntityName + "." + pNameColumn + " from " + QualifyName + "." + EntityName + " as " + EntityName;
                List<DbDataRecord> query = entities.CreateQuery<DbDataRecord>(sQuery).ToList();
                query.ForEach((item) =>
                {
                    IdNameModel oIdNameModel = new IdNameModel(item.GetValue(0), item.GetValue(1).ToString());
                    result.Add(oIdNameModel);
                });
            }
            return new ResultModel(result);
        }
        #endregion Public Methods
    }
}
